package pl.pw.mkmw.pnganimator.image.filter;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import pl.pw.mkmw.pnganimator.image.SImage;

/**
 *
 * A class for performing filters.
 *
 * @author MK
 */
public class Filter {

    private static final Logger LOG = Logger.getLogger(Filter.class.getName());

    /*
     * Performs filtering in time sequence. 
     * Next images are difference images to previous one.
     * 
     * Formula: (current - previous) % 256
     * 
     * consider one channel, three frames:
     * 
     * 50 50 50 | 50 51 49 | 50 51 49
     * 25 25 25 | 50 27 23 | 50 127 23
     * 50 50 50 | 50 50 50 | 50 50 50
     * 
     * are filtered into into:
     * 50 50 50 | 0  1 255  | 0  0  0
     * 25 25 25 | 25 2 254  | 0 100 0
     * 50 50 50 | 0  0  0  | 0  0  0
     */
    public List<SImage> filterSimpleFuture(List<SImage> raw_images) {
        List<SImage> filteredImages = new ArrayList<SImage>();

        /* add first image, not filtered */
        filteredImages.add(raw_images.get(0));

        /* next images will be filtered as difference to previous one */
        for (int i = 1; i < raw_images.size(); i++) {
            int[][][] colors = calculateDifference(raw_images.get(i - 1).getColor(), raw_images.get(i).getColor());
            filteredImages.add(new SImage(colors[0], colors[1], colors[2], colors[3]));
        }

        return filteredImages;
    }

    /*
     * Defilters future filter
     * 
     * Formula : (current + previous) % 256
     */
    public List<SImage> defilterSimpleFuture(List<SImage> filteredImages) {
        List<SImage> defilteredImages = new ArrayList<SImage>();

        /* add first image, not filtered */
        defilteredImages.add(filteredImages.get(0));

        /* next images will be defiltered as difference to previous one */
        for (int i = 1; i < filteredImages.size(); i++) {
            SImage pi = defilteredImages.get(i - 1);
            int[][][] prev = new int[][][]{pi.getRed(), pi.getGreen(), pi.getBlue(), pi.getAlpha()};
            SImage ni = filteredImages.get(i);
            int[][][] next = new int[][][]{ni.getRed(), ni.getGreen(), ni.getBlue(), ni.getAlpha()};

            Color[][] colors = decalculateDifference(prev, next);

            defilteredImages.add(new SImage(colors));
        }

        return defilteredImages;
    }

    /*
     * Used to calculate whole image difference.
     * returns int[][][] because Color cannot have negative components.
     */
    private int[][][] calculateDifference(Color[][] previous, Color[][] current) {
        int[][][] toReturn = new int[4][previous.length][previous[0].length];

        for (int y = 0; y < previous.length; y++) {
            for (int x = 0; x < previous[0].length; x++) {

                toReturn[0][y][x] = (current[y][x].getRed() - previous[y][x].getRed()) % 256;
                toReturn[1][y][x] = (current[y][x].getGreen() - previous[y][x].getGreen()) % 256;
                toReturn[2][y][x] = (current[y][x].getBlue() - previous[y][x].getBlue()) % 256;
                toReturn[3][y][x] = (current[y][x].getAlpha() - previous[y][x].getAlpha()) % 256;
            }
        }

        return toReturn;
    }

    private Color[][] decalculateDifference(int[][][] previous, int[][][] current) {
        Color[][] toReturn = new Color[previous[0].length][previous[0][0].length];

        for (int y = 0; y < previous[0].length; y++) {
            for (int x = 0; x < previous[0][0].length; x++) {

                int red = (previous[0][y][x] + current[0][y][x]) % 256;
                int green = (previous[1][y][x] + current[1][y][x]) % 256;
                int blue = (previous[2][y][x] + current[2][y][x]) % 256;
                int alpha = (previous[3][y][x] + current[3][y][x]) % 256;
                toReturn[y][x] = new Color(red, green, blue, alpha);
            }
        }

        return toReturn;
    }
}
